<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>对象创建的方式(Method of object creation)</title>
  <!-- 
  在 JavaScript 中，有多种方法可以创建对象。以下是常见的对象创建方法的说明与总结：
  1. 对象字面量

  - 概念：使用大括号  `{}`  创建一个对象，直接定义其属性和方法。
    const person = {
      name: '张三',
      age: 30,
      greet: function() {
        console.log('你好, ' + this.name);
      }
    };
    person.greet(); // 输出：你好, 张三
  - 总结：对象字面量是最简单和最常用的对象创建方式，适合创建简单的对象。

  2. 构造函数
  - 概念：使用函数作为构造函数，通过  `new`  关键字创建对象实例。
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.greet = function() {
        console.log('你好, ' + this.name);
      };
    }

    const person1 = new Person('李四', 25);

  - 总结：构造函数适合创建多个相似对象的实例，具有更好的可重用性。

  3. Object.create() 方法
  - 概念：使用  `Object.create()`  方法创建一个新对象，指定其原型对象。
    const personPrototype = {
      greet: function() {
        console.log('你好, ' + this.name);
      }
    };

    const person2 = Object.create(personPrototype);
    person2.name = '王五';

  - 总结： `Object.create()`  方法可以创建具有指定原型的新对象，适合实现原型链继承。

  4. 类 (Class)
  - 概念：使用 ES6 的  `class`  语法定义类，通过  `new`  关键字创建对象实例。
    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      greet() {
        console.log('你好, ' + this.name);
      }
    }

    const person3 = new Person('赵六', 28);

  - 总结：类提供了更清晰的语法结构，适合创建复杂的对象和实现继承。

  5. 工厂函数
  - 概念：使用函数返回一个新对象，适合创建多个对象实例。

    function createPerson(name, age) {
      return {
        name: name,
        age: age,
        greet: function() {
          console.log('你好, ' + this.name);
        }
      };
    }

    const person4 = createPerson('钱七', 32);

  - 总结：工厂函数是一种灵活的对象创建方式，适合不需要使用  `new`  关键字的场景。

  总结
  JavaScript 提供了多种对象创建方法，包括对象字面量、构造函数、 `Object.create()` 、类和工厂函数。每种方法都有其适用场景，开发者可以根据具体需求选择合适的对象创建方式，以提高代码的可读性和可维护性。
  -->
</head>
<body>

  <script>
    // 1. 对象字面量
    const person1 = {
      name: '张三',
      age: 25,
      greet: function() {
        console.log('你好, ' + this.name);
      }
    };

    person1.greet();

    // 2. 构造函数 
    /**
     * 在函数中的this一般指向某一个对象, 如果一个函数被new操作符调用, 那么this就会指向被创建的对象
     * 1. 函数执行时，浏览器会默认创建一个新的空对象
     * 2. 将this指向这个空对象
     * 3. 通过this向对象中添加属性和方法
     * 4. 函数执行完毕，如果没有明确则返回一个非空对象, 指向的对象会自动返回
     */
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.greet = function() {
        console.log('你好, ' + this.name);
      }
    }

    const person2 = new Person('李四', 30);
    person2.greet();

    // 3. Object.create() - 原型继承
    const personPrototype = {
      greet: function() {
        console.log('你好, ' + this.name);
      }
    };

    const person5 = Object.create(personPrototype);
    person5.name = '王五';
    person5.age = 35;

    // 4. 类
    class Person3 {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }

      greet() {
        console.log('你好, ' + this.name);
      }
    }

    const person3 = new Person3('赵六', 40);
    person3.greet();

    // 5. 工厂函数
    function createPerson(name, age) {
      const person = {};
      person.name = name;
      person.age = age;
      person.greet = function() {
        console.log('你好, ' + this.name);
      };
      return person;
    }

    const person4 = createPerson('钱七', 45);
    person4.greet();

    // 6. 函数补充 - 函数也是对象
    // 6.1 原始类型数据
    const num = 10; // 栈内存
    console.log(typeof num); // number

    // 6.2 对象类型数据 - 内存引用: 地址 - 指针 - 引用
    const obj = {}; // 堆内存
    console.log(typeof obj); // object

    // 6.3 函数类型数据
    function fnData() {} // 堆内存
    console.log(typeof fnData); // function -> object

    // 6.4 函数也是对象
    function Person4(name, age) {
      this.name = name;
      this.age = age;
    }

    Person4.prototype.greet = function() {
      console.log('你好, ' + this.name);
    };

    const person6 = new Person4('孙八', 50);
    person6.greet();

    // 构造函数上和类上面添加的函数, 称为: 类方法
    fnData.move = function() {
      console.log('move');
    };

    fnData.move();

    
  </script>
  
</body>
</html>